/*
* Sun Public License Notice
*
* The contents of this file are subject to the Sun Public License
* Version 1.0 (the "License"). You may not use this file except in
* compliance with the License. A copy of the License is available at
* http://www.sun.com/
*
* The Original Code is Forte for Java, Community Edition. The Initial
* Developer of the Original Code is Sun Microsystems, Inc. Portions
* Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved.
*/
package org.netbeans.core.execution;
import java.io.FileDescriptor;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.net.URL;
import java.security.Permission;
import java.util.*;
import java.lang.reflect.Field;
import org.openide.execution.NbClassLoader;
import ice.iblite.BrowserClassLoader;
/** See java.lang.SecurityManager for more details.
*
* @author Ales Novak
*/
public class TopSecurityManager extends SecurityManager {
/** thread group of executed classes */
private ThreadGroup base;
/**
* constructs new TopSecurityManager
*/
public TopSecurityManager () {
base = ExecutionEngine.base;
}
public void checkExit(int status) throws SecurityException {
ThreadGroup g = Thread.currentThread().getThreadGroup ();
ThreadGroup old = null;
while (g != null && g != base) {
old = g;
g = g.getParent ();
}
IOPermissionCollection iopc;
iopc = AccController.getIOPermissionCollection();
if (g != null) { // g == base
if (old instanceof TaskThreadGroup) {
if (iopc != null) {
ExecutionEngine.getTaskIOs().free(old, iopc.getIO()); // closes output
} // else loaded by App classloader
ExecutionEngine.closeGroup(old);
stopTaskThreadGroup((TaskThreadGroup) old);
}
} else {
if ((iopc != null) &&
(iopc.grp != null)) {
ExecutionEngine.getTaskIOs().free(iopc.grp, iopc.getIO()); // closes output
ExecutionEngine.closeGroup(iopc.grp);
stopTaskThreadGroup(iopc.grp);
throw new ExitSecurityException();
}
if (isNbClassLoader()) {
throw new SecurityException();
}
}
super.checkExit(status);
}
public boolean checkTopLevelWindow(Object window) {
IOPermissionCollection iopc = AccController.getIOPermissionCollection();
if (iopc != null && iopc.grp != null && (window instanceof java.awt.Window)) {
ExecutionEngine.putWindow((java.awt.Window) window, iopc.grp);
}
return super.checkTopLevelWindow(window);
}
/** Hack against permissions of Launcher$AppLoader. */
public void checkPackageAccess(String pckg) {
if (pckg == null) return;
if (pckg.startsWith("sun.")) { // NOI18N
if (inClazz("sun.misc.Launcher") || inClazz("java.lang.Class")) { // NOI18N
return;
}
}
super.checkPackageAccess(pckg);
}
/* ----------------- private methods ------------- */
private boolean inClazz(String s) {
Class[] classes = getClassContext();
int i = 0;
for (; (i < classes.length) && (classes[i] == TopSecurityManager.class); i++);
if (i == classes.length) {
return false;
}
return classes[i].getName().startsWith(s);
}
private void stopTaskThreadGroup(TaskThreadGroup old) {
synchronized(old) {
int count = old.activeCount();
int icurrent = -1;
Thread current = Thread.currentThread();
Thread[] thrs = new Thread[count];
old.enumerate(thrs, true);
for (int i = 0; i < thrs.length; i++) {
if (thrs[i] == null) break;
if (thrs[i] == current) icurrent = i;
else thrs[i].stop();
}
if (icurrent != -1) thrs[icurrent].stop();
//throw new ExitSecurityException();
}
}
public void checkRead(String name) {
if (isForeignClassLoader()) {
super.checkRead(name);
}
}
public void checkRead(String file, Object context) {
if (isForeignClassLoader()) {
super.checkRead(file, context);
}
}
public void checkWrite(String file) {
if (isForeignClassLoader()) {
super.checkWrite(file);
}
}
public void checkDelete(String file) {
if (isForeignClassLoader()) {
super.checkDelete(file);
}
}
public void checkRead(FileDescriptor fd) {
}
public void checkWrite(FileDescriptor fd) {
}
public synchronized void checkConnect(String host, int port) {
ClassLoader cloader = getForeignClassLoader();
if (cloader != null) {
Object ctx = BrowserClassLoader.getSecurityContext(cloader);
if (ctx instanceof URL) {
try {
check = false;
String fromHost = ((URL) ctx).getHost();
InetAddress ia2 = InetAddress.getByName(host);
InetAddress ia3 = InetAddress.getByName(fromHost);
if (ia2.equals(ia3)) {
return;
}
} catch (UnknownHostException e) { // ignore
if (Boolean.getBoolean("netbeans.debug.security")) { // NOI18N
e.printStackTrace();
}
} finally {
check = true;
}
}
super.checkConnect(host, port);
}
}
public void checkConnect(String s, int port, Object context) {
checkConnect(s, port);
}
public void checkPermission(Permission perm) {
if (isForeignClassLoader ()) {
super.checkPermission (perm);
}
}
public void checkPermission(Permission perm, Object context) {
if (isForeignClassLoader ()) {
super.checkPermission (perm, context);
}
}
public void checkMemberAccess(Class clazz, int which) {
if (which == java.lang.reflect.Member.PUBLIC) {
return;
} else {
super.checkMemberAccess(clazz, which);
}
}
/** @return true iff an instance of the NbClassLoader class is on the stack
*/
protected boolean isNbClassLoader() {
Class[] ctx = getClassContext();
ClassLoader cloader;
for (int i = ctx.length; --i >= 0; ) {
if (ctx[i].getClassLoader() instanceof NbClassLoader) {
return true;
}
}
return false;
}
protected synchronized boolean isForeignClassLoader() {
return (getForeignClassLoader() != null);
}
private ClassLoader getForeignClassLoader() {
if (! check) {
return null;
}
try {
check = false;
Class[] secureArray = getSecure ();
int secureArrayLength = secureArray.length;
Class[] ctx = getClassContext();
ClassLoader cloader;
LOOP: for (int i = 0; i < ctx.length; i++) {
if (ClassLoader.class.isAssignableFrom(ctx[i])) {
//System.out.println("TRYING A CLASSLOADER: " + ctx[i]); // NOI18N
}
if (ctx[i] == getAccessControllerClass()) {
// privileged action is on the stack before an untrusted class loader
// #3950
return null;
} else if ((cloader = ctx[i].getClassLoader()) != null) {
final Class hisClass = cloader.getClass();
for (int j = 0; j < secureArrayLength; j++) {
if (secureArray[j] == hisClass) {
if (ClassLoader.class.isAssignableFrom(ctx[i])) { // foreign classloader does work
return null;
} else {
continue LOOP;
}
}
}
if (isSecureClass(ctx[i])) {
if (ClassLoader.class.isAssignableFrom(ctx[i])) {
return null;
} else {
continue LOOP;
}
}
// is foreign
if (System.getProperty ("netbeans.debug.security") != null) {
System.err.println("Not secure class loader: " + hisClass);
}
return cloader;
} else if (ClassLoader.class.isAssignableFrom(ctx[i])) { // cloader == null
return null; // foreign classloader wants to do work...
}
}
} finally {
check = true;
}
return null;
}
/** Checks if the class is loaded through the nbfs URL */
static boolean isSecureClass(final Class clazz) {
java.security.PrivilegedAction run = new java.security.PrivilegedAction() {
public Object run() {
URL url = clazz.getProtectionDomain().getCodeSource().getLocation();
if (url != null) {
return isSecureProtocol(url.getProtocol());
} else {
// [PENDING] remove this else if iceblit is not used
String s = getClassURLProtocol(clazz);
if (s != null) {
return isSecureProtocol(s);
} else {
return Boolean.FALSE; // none CodeSource -> be conservative
}
}
}
};
return ((Boolean) java.security.AccessController.doPrivileged(run)).booleanValue();
}
/** @return a protocol through which was the class loaded (file://...) or null
* [PENDING] remove this method if iceblit is not used
*/
static String getClassURLProtocol(Class clazz) {
if (clazz.getClassLoader().getClass().
getName().indexOf("ice.iblite.BrowserClassLoader") >= 0) { // NOI18N
try {
Field fld = getUrlField(clazz.getClassLoader().getClass());
if (fld == null) {
return null;
} else {
URL url = (URL) fld.get(clazz.getClassLoader());
if (url != null) {
return url.getProtocol();
}
}
} catch (Exception e) {
if (Boolean.getBoolean("netbeans.debug.exceptions")) { // NOI18N
e.printStackTrace();
}
}
}
return null;
}
static Field getUrlField(Class clazz) {
if (urlField == null) {
try {
Field[] fds = clazz.getDeclaredFields();
for (int i = 0; i < fds.length; i++) {
if (fds[i].getType() == java.net.URL.class) {
fds[i].setAccessible(true);
urlField = fds[i];
}
}
} catch (Exception e) {
if (Boolean.getBoolean("netbeans.debug.security")) { // NOI18N
e.printStackTrace();
}
}
}
return urlField;
}
private static Field urlField;
/** @return Boolean.TRUE iff the string is a safe protocol (file, nbfs, ...) */
static Boolean isSecureProtocol(String protocol) {
if (protocol.equals("http") || // NOI18N
protocol.equals("rmi")) { // NOI18N
return Boolean.FALSE;
}
if (protocol.equals("nbfs") || // NOI18N
protocol.equals("file") || // NOI18N
protocol.equals("systemresource") || // NOI18N
protocol.equals("jar:file")) { // NOI18N
return Boolean.TRUE;
} else {
return Boolean.FALSE;
}
}
private static Class[] secureArray;
private static Class accessControllerClass;
/** Array of secure class loaders.
*/
private static Class[] getSecure () {
if (secureArray != null) {
return secureArray;
}
if (secureArray != null) {
return secureArray;
}
secureArray = new Class[] {
forName ("sun.misc.Launcher$AppClassLoader"), // NOI18N
forName ("sun.misc.Launcher$ExtClassLoader"), // NOI18N
forName ("org.netbeans.core.ModuleClassLoader"), // NOI18N
forName ("org.netbeans.core.ClassLoaderSupport"), // NOI18N
org.openide.execution.NbClassLoader.class,
forName ("sun.rmi.server.LoaderHandler$Loader"), // NOI18N
forName("COM.jbms._104._735") // NOI18N
};
return secureArray;
}
/** @return java.security.AccessController.class */
static Class getAccessControllerClass() {
if (accessControllerClass == null) {
accessControllerClass = forName("java.security.AccessController"); // NOI18N
}
return accessControllerClass;
}
private static Class forName (String fn) {
try {
return Class.forName (fn);
} catch (ClassNotFoundException ex) {
if (Boolean.getBoolean("netbeans.debug.security")) { // NOI18N
ex.printStackTrace();
}
return null;
}
}
private static boolean check;
static {
if (Boolean.getBoolean("netbeans.security.nocheck")) { // NOI18N
check = false;
} else {
check = true;
}
}
}
/*
* Log
* 27 src-jtulach1.26 1/20/00 Petr Hamernik rolled back
* 26 src-jtulach1.25 1/19/00 Petr Nejedly Commented out debug
* messages
* 25 src-jtulach1.24 1/13/00 Jaroslav Tulach I18N
* 24 src-jtulach1.23 1/12/00 Ales Novak i18n
* 23 src-jtulach1.22 12/20/99 Ales Novak checkRead/Write/Delete
* is back - FilePermissions are skipped
* 22 src-jtulach1.21 12/14/99 Ales Novak simplified security
* 21 src-jtulach1.20 11/5/99 Ales Novak secure protocols
* 20 src-jtulach1.19 11/1/99 Ales Novak cloudscape classloader
* added into a list of trusted classloaders
* 19 src-jtulach1.18 10/22/99 Ian Formanek NO SEMANTIC CHANGE - Sun
* Microsystems Copyright in File Comment
* 18 src-jtulach1.17 10/8/99 Ales Novak security checks
* 17 src-jtulach1.16 10/6/99 Ales Novak dumpStack removed
* 16 src-jtulach1.15 10/5/99 Ales Novak #4166
* 15 src-jtulach1.14 10/1/99 Martin Ryzl "RMIClassLoader" added
* to secure classloaders
* 14 src-jtulach1.13 9/10/99 Jaroslav Tulach Does not use any weak
* maps.
* 13 src-jtulach1.12 9/2/99 Jaroslav Tulach ClassLoaderSupport is
* trusted too.
* 12 src-jtulach1.11 9/1/99 Jaroslav Tulach Treats jars in extension
* directory as trusted.
* 11 src-jtulach1.10 8/31/99 Jaroslav Tulach Works not only for
* Launcher$AppLoader, but also for Launcher$ExtLoader
* 10 src-jtulach1.9 8/31/99 Jaroslav Tulach checkPermisson only for
* foreign loaders
* 9 src-jtulach1.8 8/30/99 Ales Novak applet security
* 8 src-jtulach1.7 8/6/99 Ales Novak NullPointerExc
* 7 src-jtulach1.6 7/28/99 Ales Novak new window system/#1409
* 6 src-jtulach1.5 7/28/99 Ales Novak bugfix #1409
* 5 src-jtulach1.4 7/9/99 Ales Novak #2413 fix
* 4 src-jtulach1.3 6/3/99 Ales Novak security checks disabled
* 3 src-jtulach1.2 4/10/99 Ales Novak
* 2 src-jtulach1.1 4/8/99 Ales Novak
* 1 src-jtulach1.0 3/31/99 Ales Novak
* $
*/